package com.tianji.promotion.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.promotion.domain.dto.CouponFormDTO;
import com.tianji.promotion.domain.dto.CouponIssueFormDTO;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.CouponScope;
import com.tianji.promotion.domain.po.UserCoupon;
import com.tianji.promotion.domain.query.CouponQuery;
import com.tianji.promotion.domain.vo.CouponPageVO;
import com.tianji.promotion.domain.vo.CouponScopeVO;
import com.tianji.promotion.domain.vo.CouponVO;
import com.tianji.promotion.enums.CouponScopeStatus;
import com.tianji.promotion.enums.CouponStatus;
import com.tianji.promotion.enums.ObtainType;
import com.tianji.promotion.mapper.CouponMapper;
import com.tianji.promotion.service.ICouponScopeService;
import com.tianji.promotion.service.ICouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.service.IExchangeCodeService;
import com.tianji.promotion.service.IUserCouponService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 优惠券的规则信息 服务实现类
 * </p>
 *
 * @author niu
 */
@Service
@Slf4j
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {




    @Autowired
    private ICouponScopeService scopeService;


    @Autowired
    private IExchangeCodeService codeService;


    @Autowired
    private IUserCouponService userCouponService;
    /**
     * 查询系统中的优惠券
     * 1）发放中,不能过期的
     * 2）手动领取
     * */
    @Override
    public List<CouponVO> couponList() {
        LambdaQueryWrapper<Coupon> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Coupon::getStatus, CouponStatus.ISSUING.getValue());
        queryWrapper.eq(Coupon::getObtainWay, ObtainType.PUBLIC.getValue());
        List<Coupon> couponList = this.list(queryWrapper);
        if(CollUtil.isEmpty(couponList)){
            return null;
        }
        List<CouponVO> voList = BeanUtil.copyToList(couponList, CouponVO.class);
        // 查询用户领券列表
        Long userId = UserContext.getUser();
        if (userId == null) {
            for (CouponVO couponVO : voList) {
                couponVO.setReceived(false);
                couponVO.setAvailable(true);
            }
            return voList;
        }
        List<UserCoupon> userCouponList = userCouponService.lambdaQuery()
                .eq(UserCoupon::getUserId, userId)
                .in(UserCoupon::getStatus, Arrays.asList(1,2))
                .list();
        if(CollUtil.isEmpty(userCouponList)){
            userCouponList = new ArrayList<>();
        }
        Map<Long, List<UserCoupon>> userCouponMap = userCouponList.stream().collect(Collectors.groupingBy(UserCoupon::getCouponId));
        for (CouponVO couponVO : voList) {
            Integer userLimit = couponVO.getUserLimit();
            List<UserCoupon> userCoupons = userCouponMap.get(couponVO.getId());
            int takeCount = CollUtils.isEmpty(userCoupons)?0:userCoupons.size();
            // 是否可领取，用户已经领用数量 《 每个用户最大限领数量 && 券的总的已经领用数量 《 券的最大数量
            couponVO.setAvailable(takeCount < userLimit && couponVO.getIssueNum() < couponVO.getTotalNum());
            // 是否可以使用，已经领取 && 没有使用 数量  》 0
            int unusedCount = (int)(CollUtils.isEmpty(userCoupons)?0:userCoupons.stream().map(uc->Objects.equals(uc.getStatus(), 1)).count());
            couponVO.setReceived(unusedCount > 0);
        }
        return voList;
    }

    @Override
    @Transactional
    public void saveCoupon(CouponFormDTO dto) {
        Long userId = UserContext.getUser();
        // dto -> coupon， status=1
        Coupon coupon = BeanUtil.copyProperties(dto, Coupon.class);
        coupon.setStatus(CouponStatus.DRAFT);
        coupon.setCreateTime(LocalDateTime.now());
        coupon.setUpdateTime(LocalDateTime.now());
        coupon.setCreater(userId);
        coupon.setUpdater(userId);
        // 保存到coupon表
        this.save(coupon);
        // 判断是否限定了范围
        if(!dto.getSpecific()){
            return;
        }
        // 如果是，保存到coupon_scope表
        List<Long> scopes = dto.getScopes();
        if(CollUtil.isEmpty(scopes)){
            throw new BadRequestException("范围不能为空");
        }
        List<CouponScope> scopeList = new ArrayList<>(scopes.size());
        for (Long scope : scopes) {
            CouponScope couponScope = new CouponScope();
            couponScope.setType(CouponScopeStatus.CATEGORY.getValue());
            couponScope.setBizId(scope);
            couponScope.setCouponId(coupon.getId());
            scopeList.add(couponScope);
        }
        scopeService.saveBatch(scopeList);
    }

    @Override
    public PageDTO<CouponPageVO> pageCoupon(CouponQuery query) {
        Page<Coupon> page = query.toMpPage("create_time", false);
        LambdaQueryWrapper<Coupon> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(query.getStatus()!=null, Coupon::getStatus, query.getStatus())
                .eq(query.getType()!=null, Coupon::getType, query.getType())
                .like(StringUtils.isNotBlank(query.getName()), Coupon::getName, query.getName());
        this.page(page, queryWrapper);
        List<Coupon> records = page.getRecords();
        List<CouponPageVO> voList = BeanUtil.copyToList(records, CouponPageVO.class);
        PageDTO<CouponPageVO> couponList = new PageDTO<>();
        couponList.setList(voList);
        couponList.setTotal(page.getTotal());
        return couponList;
    }

    @Override
    public void issue(Long id, CouponIssueFormDTO dto) {
        // 根据id查询coupon
        Coupon couponDB = this.getById(id);
        if(couponDB == null){
            throw new BizIllegalException("优惠券不存在");
        }
        if(dto.getIssueBeginTime() == null){
            dto.setIssueBeginTime(LocalDateTime.now());
        }
        // 发放
        Coupon coupon = BeanUtil.copyProperties(dto, Coupon.class);
        LocalDateTime issueBeginTime = dto.getIssueBeginTime();
        LocalDateTime now = LocalDateTime.now();
        if(issueBeginTime.isAfter(now)){
            coupon.setStatus(CouponStatus.UN_ISSUE);
        }else{
            coupon.setStatus(CouponStatus.ISSUING);
        }

        coupon.setUpdateTime(LocalDateTime.now());
        this.updateById(coupon);
        // 兑换码
        ObtainType obtainWay = couponDB.getObtainWay();
        if(!Objects.equals(ObtainType.ISSUE, obtainWay) ||
                !Objects.equals(CouponStatus.DRAFT,couponDB.getStatus())){
            return;
        }
        //TODO 生成兑换码
        codeService.asyncGenerateCode(id, dto.getIssueEndTime(), couponDB.getTotalNum());
    }

    @Override
    public void updateCoupons(Long id, CouponFormDTO dto) {
        Coupon coupon = BeanUtil.copyProperties(dto, Coupon.class);
        coupon.setUpdateTime(LocalDateTime.now());
        Long userId = UserContext.getUser();
        coupon.setUpdater(userId);
        coupon.setUpdateTime(LocalDateTime.now());
        this.updateById(coupon);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCoupons(Long id) {
        // 根据id查询coupon
        Coupon couponDB = this.getById(id);
        if(BeanUtil.isEmpty(couponDB)){
            throw new BizIllegalException("未查询到优惠券信息");
        }
        if(!Objects.equals(couponDB.getStatus(),CouponStatus.DRAFT)){
            throw new BizIllegalException("优惠券状态不允许删除");
        }
        this.removeById(id);
        scopeService.remove(new LambdaQueryWrapper<CouponScope>().eq(CouponScope::getCouponId, id));
    }

    @Override
    public CouponPageVO getCouponsById(Long id) {

        Coupon couponDB = this.getById(id);
        if(BeanUtil.isEmpty(couponDB)){
            throw new BizIllegalException("未查询到优惠券信息");
        }
        CouponPageVO couponPageVO = BeanUtil.copyProperties(couponDB, CouponPageVO.class);
        if(couponPageVO.getSpecific()){
            List<CouponScope> list = scopeService.list(new LambdaQueryWrapper<CouponScope>().eq(CouponScope::getCouponId, id));
            if(CollUtil.isNotEmpty(list)){
                ArrayList<CouponScopeVO> couponScopeVOS = new ArrayList<>();
                for (CouponScope couponScope : list) {
                    CouponScopeVO couponScopeVO = new CouponScopeVO();
                    couponScopeVO.setId(couponScope.getBizId());
                    couponScopeVOS.add( couponScopeVO);
                }
            }
        }
        return couponPageVO;
    }

    @Override
    public void updateCouponsStatus(Long id) {
        Coupon couponDB = this.getById(id);
        if(BeanUtil.isEmpty(couponDB)){
            throw new BizIllegalException("未查询到优惠券信息");
        }
        if(!Objects.equals(couponDB.getStatus(),CouponStatus.ISSUING)){
            throw new BizIllegalException("优惠券状态不允许删除");
        }
        couponDB.setStatus(CouponStatus.PAUSE);
        this.updateById(couponDB);
    }
}
